//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using Microsoft.Research.ScientificWorkflow.Helper;

namespace Microsoft.Research.ScientificWorkflow.Activities
{
    /// <summary>
    /// This activity allows addins selections to an open dap query.
    /// Selections are the conditions which can be specified to limit the
    /// data read based on conditions. For instance to read data from a
    /// file with tempratures above a certain value an appropriate selection
    /// can be appened to the uri.
    /// Selections are added to the end of the uri after the projections.
    /// There can be more than one selection applied to a single DAP query. However
    /// a single selection activity supports only one selection condition. To
    /// add more selections more instances of this activity should be included in the
    /// WF.
    /// </summary>
    [Name("OpenDap Selections Builder")]
    [Description("Constructs the selection clauses in the query. The clauses are added to the query string before executing on the server.")]
    [WorkflowCategory("OpenDap")]
    class OpenDAPSelections : Activity
    {
        #region Property Definitions

        public static DependencyProperty InputDAPUriProperty = DependencyProperty.Register("InputDAPUri",
            typeof(OpenDAPURI), typeof(OpenDAPSelections));

        /// <summary>
        /// Input Open DAP Uri generated after appending the server name
        /// and the file name.
        /// </summary>
        [RequiredInputParam]
        [Name("Input Open DAP Uri")]
        [Description("Input Open DAP Uri for adding the selections.")]
        public OpenDAPURI InputDAPUri
        {
            get { return ((OpenDAPURI)(base.GetValue(OpenDAPSelections.InputDAPUriProperty))); }
            set { base.SetValue(OpenDAPSelections.InputDAPUriProperty, value); }
        }

        public static DependencyProperty VariableNameProperty = DependencyProperty.Register("VariableName",
            typeof(string), typeof(OpenDAPSelections));

        /// <summary>
        /// Name of the variable for which the selection is to be added.
        /// </summary>
        [RequiredInputParam]
        [Name("Selection Variable Name")]
        [Description("Variable name for selection.")]
        public string VariableName
        {
            get { return ((string)(base.GetValue(OpenDAPSelections.VariableNameProperty))); }
            set { base.SetValue(OpenDAPSelections.VariableNameProperty, value); }
        }

        public static DependencyProperty ValuesProperty = DependencyProperty.Register("Values",
            typeof(string), typeof(OpenDAPSelections));

        /// <summary>
        /// Comma seperated values to be used for the selection.
        /// </summary>
        [RequiredInputParam]
        [Name("Selection Values")]
        [Description("Values to be used for the selection condition.")]
        public string Values
        {
            get { return ((string)(base.GetValue(OpenDAPSelections.ValuesProperty))); }
            set { base.SetValue(OpenDAPSelections.ValuesProperty, value); }
        }

        public static DependencyProperty SelectionTypeProperty = DependencyProperty.Register("SelectionType",
            typeof(string), typeof(OpenDAPSelections));

        /// <summary>
        /// Type of selection to be added to the URL. This depends on the
        /// variable type. If there is a mismatch then this activity will
        /// not throw an error. Error will be thrown before the query for
        /// fetching data would be executed.
        /// </summary>
        [RequiredInputParam]
        [Name("Selection Type")]
        [Description("Type of selection to be applied.")]
        public string SelectionType
        {
            get { return ((string)(base.GetValue(OpenDAPSelections.SelectionTypeProperty))); }
            set { base.SetValue(OpenDAPSelections.SelectionTypeProperty, value); }
        }
        
        public static DependencyProperty OutputDAPUriProperty = DependencyProperty.Register("OutputDAPUri",
            typeof(OpenDAPURI), typeof(OpenDAPSelections));

        /// <summary>
        /// Input Open DAP Uri generated after appending the server name
        /// and the file name.
        /// </summary>
        [OutputParam]
        [Name("Output Open DAP Uri")]
        [Description("Output Open DAP Uri with selections.")]
        public OpenDAPURI OutputDAPUri
        {
            get { return ((OpenDAPURI)(base.GetValue(OpenDAPSelections.OutputDAPUriProperty))); }
            set { base.SetValue(OpenDAPSelections.OutputDAPUriProperty, value); }
        }

        #endregion

        #region Overridden methods

        
        /// <summary>
        /// Adds the selection values to the dapuri object. To do
        /// so this class uses the querbuilder class.
        /// </summary>
        /// <param name="executionContext"></param>
        /// <returns></returns>
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            string[] selectionValues = ParseValues();

            int index = this.InputDAPUri.GetVariableIndex(this.VariableName);
            if(-1 == index)
                throw new ArgumentException("Selection cannot be added for non existent variables");

            OpenDAPURI.DAPOperators dapOper =
                (OpenDAPURI.DAPOperators)Enum.Parse(typeof(OpenDAPURI.DAPOperators), this.SelectionType);
            this.InputDAPUri.AddSelection(index, new Selection(dapOper, selectionValues));
            this.OutputDAPUri = this.InputDAPUri;

            return ActivityExecutionStatus.Closed;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// This method tokenizes the values string to generate
        /// a string array.
        /// </summary>
        /// <returns></returns>
        private string[] ParseValues()
        {
            if (string.IsNullOrEmpty(this.Values))
                throw new ArgumentException("Required input parameter not set.");

            return (this.Values).Split(new char[] { ',' });
        }

        #endregion
    }
}
